1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12
13 package org.apache.tapestry5.func;
14
15 import java.util.Collection;
16 import java.util.Comparator;
17 import java.util.Iterator;
18 import java.util.Map;
19 import java.util.Map.Entry;
20
21 /**
22 * Functional operations on collections with generics support. The core interface is {@link Flow} to
23 * which operations
24 * and transformations
25 * (in terms of {@link Predicate}s, {@link Mapper}s and {@link Reducer}s) to create new Flows. Flows
26 * are initially
27 * created
28 * using {@link #flow(Collection)} and {@link #flow(Object...)}.
29 *
30 * F will be used a bit, thus it has a short name (for those who don't like static imports). It provides a base set of
31 * Predicate, Mapper and Reducer factories. A good development pattern for applications is to provide a similar,
32 * application-specific, set of such factories.
33 *
34 * @since 5.2.0
35 */
36 @SuppressWarnings("all")
37 public class F
38 {
39 final static Flow<?> EMPTY_FLOW = new EmptyFlow();
40
41 @SuppressWarnings("unchecked")
42 static <T> Flow<T> emptyFlow()
43 {
44 return (Flow<T>) EMPTY_FLOW;
45 }
46
47 /**
48 * A Predicate factory for equality of an element from a flow against a specified
49 * value.
50 */
51 public static <T> Predicate<T> eql(final T value)
52 {
53 return new Predicate<T>()
54 {
55 @Override
56 public boolean accept(T element)
57 {
58 return element.equals(value);
59 }
60 };
61 }
62
63 /**
64 * Predicate that returns true if the provided string is blank (null or all whitespace).
65 */
66 public static Predicate<String> IS_BLANK = new Predicate<String>()
67 {
68 @Override
69 public boolean accept(String element)
70 {
71 return element == null || element.trim().length() == 0;
72 }
73 };
74
75 /**
76 * A Predicate factory for comparison of a Comparable element from a flow against a fixed value.
77 */
78 public static <T extends Comparable<T>> Predicate<T> eq(final T value)
79 {
80 return new Predicate<T>()
81 {
82 @Override
83 public boolean accept(T element)
84 {
85 return element.compareTo(value) == 0;
86 }
87 };
88 }
89
90 /**
91 * A Predicate factory for comparison of a Comparable element against a fixed value.
92 */
93 public static <T extends Comparable<T>> Predicate<T> neq(final T value)
94 {
95 return new Predicate<T>()
96 {
97 @Override
98 public boolean accept(T object)
99 {
100 return object.compareTo(value) != 0;
101 }
102 };
103 }
104
105 /**
106 * A Predicate factory for comparison of a Comparable against a fixed value; true
107 * if the flow element is greater than the provided value.
108 */
109 public static <T extends Comparable<T>> Predicate<T> gt(final T value)
110 {
111 return new Predicate<T>()
112 {
113 @Override
114 public boolean accept(T element)
115 {
116 return element.compareTo(value) > 0;
117 }
118 };
119 }
120
121 /**
122 * A Predicate factory for comparison of a Comparable against a fixed value; true
123 * if the flow element is greater than or equal to the value.
124 */
125 public static <T extends Comparable<T>> Predicate<T> gteq(final T value)
126 {
127 return new Predicate<T>()
128 {
129 @Override
130 public boolean accept(T element)
131 {
132 return element.compareTo(value) >= 0;
133 }
134 };
135 }
136
137 /**
138 * A Predicate factory for comparison of a Comparable against a fixed value; true
139 * if the element is less than the value.
140 */
141 public static <T extends Comparable<T>> Predicate<T> lt(T value)
142 {
143 return not(gteq(value));
144 }
145
146 /**
147 * A Predicate factory for comparison of a Comprable element against a fixed value; true
148 * if the element is less than or equal to the value.
149 */
150 public static <T extends Comparable<T>> Predicate<T> lteq(T value)
151 {
152 return not(gt(value));
153 }
154
155 /**
156 * A Predicate factory; returns true if the value from the Flow is null.
157 */
158 public static <T> Predicate<T> isNull()
159 {
160 return new Predicate<T>()
161 {
162 @Override
163 public boolean accept(T element)
164 {
165 return element == null;
166 }
167 };
168 }
169
170 /**
171 * A Predicate factory; returns true if the value from the Flow is not null.
172 */
173 public static <T> Predicate<T> notNull()
174 {
175 return not(isNull());
176 }
177
178 /**
179 * A Mapper factory that gets the string value of the flow value using {@link String#valueOf(Object)}.
180 */
181 public static <T> Mapper<T, String> stringValueOf()
182 {
183 return new Mapper<T, String>()
184 {
185 @Override
186 public String map(T value)
187 {
188 return String.valueOf(value);
189 }
190 };
191 }
192
193 /**
194 * A Mapper factory; the returned Mapper ignores its input value and always returns a
195 * predetermined result.
196 */
197 public static <S, T> Mapper<S, T> always(final T fixedResult)
198 {
199 return new Mapper<S, T>()
200 {
201 @Override
202 public T map(S input)
203 {
204 return fixedResult;
205 }
206 };
207 }
208
209 /**
210 * A Mapper factory that combines a Predicate with two {@link Mapper}s; evaluating the predicate
211 * selects one of the two mappers.
212 *
213 * @param predicate
214 * evaluated to selected a coercion
215 * @param ifAccepted
216 * used when predicate evaluates to true
217 * @param ifRejected
218 * used when predicate evaluates to false
219 */
220 public static <S, T> Mapper<S, T> select(final Predicate<? super S> predicate, final Mapper<S, T> ifAccepted,
221 final Mapper<S, T> ifRejected)
222 {
223 assert predicate != null;
224 assert ifAccepted != null;
225 assert ifRejected != null;
226
227 return new Mapper<S, T>()
228 {
229 @Override
230 public T map(S input)
231 {
232 Mapper<S, T> active = predicate.accept(input) ? ifAccepted : ifRejected;
233
234 return active.map(input);
235 }
236 };
237 }
238
239 /**
240 * Override of {@link #select(Predicate, Mapper, Mapper)} where rejected values are replaced
241 * with null.
242 */
243 public static <S, T> Mapper<S, T> select(Predicate<? super S> predicate, Mapper<S, T> ifAccepted)
244 {
245 return select(predicate, ifAccepted, (T) null);
246 }
247
248 /**
249 * Override of {@link #select(Predicate, Mapper)} where rejected values are replaced with a
250 * fixed value.
251 */
252 public static <S, T> Mapper<S, T> select(Predicate<? super S> predicate, Mapper<S, T> ifAccepted, T ifRejectedValue)
253 {
254 Mapper<S, T> rejectedMapper = always(ifRejectedValue);
255
256 return select(predicate, ifAccepted, rejectedMapper);
257 }
258
259 /**
260 * A Mapper factory; the Mapper returns the the flow value unchanged.
261 */
262 public static <S> Mapper<S, S> identity()
263 {
264 return new Mapper<S, S>()
265 {
266 @Override
267 public S map(S input)
268 {
269 return input;
270 }
271 };
272 }
273
274 /**
275 * Allows a Mapper that maps to boolean to be used as a Predicate.
276 */
277 public static <S> Predicate<S> toPredicate(final Mapper<S, Boolean> mapper)
278 {
279 assert mapper != null;
280
281 return new Predicate<S>()
282 {
283 @Override
284 public boolean accept(S object)
285 {
286 return mapper.map(object);
287 }
288 };
289 }
290
291 /**
292 * A Reducer that operates on a Flow of Integers and is used to sum the values.
293 */
294 public static Reducer<Integer, Integer> SUM_INTS = new Reducer<Integer, Integer>()
295 {
296 @Override
297 public Integer reduce(Integer accumulator, Integer value)
298 {
299 return accumulator + value;
300 }
301 };
302
303 /**
304 * A two-input Mapper used to add the values from two Flows of Integers into a Flow of Integer
305 * sums.
306 */
307 public static Mapper2<Integer, Integer, Integer> ADD_INTS = new Mapper2<Integer, Integer, Integer>()
308 {
309 @Override
310 public Integer map(Integer first, Integer second)
311 {
312 return first + second;
313 }
314 };
315
316 /**
317 * Extracts the values from the collection to form a {@link Flow}. The Collection
318 * may change after the Flow is created without affecting the Flow.
319 */
320 public static <T> Flow<T> flow(Collection<T> values)
321 {
322 assert values != null;
323
324 if (values.isEmpty())
325 return emptyFlow();
326
327 return new ArrayFlow<T>(values);
328 }
329
330 /**
331 * Creates a new Flow from the values. You should not change the values array
332 * after invoking this method (i.e., no defensive copy of the values is made).
333 */
334 public static <T> Flow<T> flow(T... values)
335 {
336 if (values.length == 0)
337 return emptyFlow();
338
339 return new ArrayFlow<T>(values);
340 }
341
342 /**
343 * Creates a lazy Flow from the {@link Iterator} obtained from the iterable. The Flow
344 * will be threadsafe as long as the iterable yields a new Iterator on each invocation <em>and</em> the underlying
345 * iterable object is not modified while the Flow is evaluating.
346 * In other words, not extremely threadsafe.
347 */
348 public static <T> Flow<T> flow(Iterable<T> iterable)
349 {
350 assert iterable != null;
351
352 return flow(iterable.iterator());
353 }
354
355 /**
356 * Creates a lazy Flow from the {@link Iterator}. The Flow will be threadsafe as long as the underlying iterable
357 * object is not modified while the Flow is evaluating. In other words, not extremely threadsafe.
358 *
359 * @since 5.3
360 */
361 public static <T> Flow<T> flow(Iterator<T> iterator)
362 {
363 return lazy(new LazyIterator<T>(iterator));
364 }
365
366 /**
367 * Creates a ZippedFlow from the provided map; the order of the tuples in the ZippedFlow is defined
368 * by the iteration order of the map entries.
369 *
370 * @param <A>
371 * type of key and first tuple value
372 * @param <B>
373 * type of value and second tuple value
374 * @param map
375 * source of tuples
376 * @return zipped flow created from map
377 * @since 5.3
378 */
379 public static <A, B> ZippedFlow<A, B> zippedFlow(Map<A, B> map)
380 {
381 assert map != null;
382
383 Flow<Tuple<A, B>> tuples = F.flow(map.entrySet()).map(new Mapper<Map.Entry<A, B>, Tuple<A, B>>()
384 {
385 @Override
386 public Tuple<A, B> map(Entry<A, B> element)
387 {
388 return Tuple.create(element.getKey(), element.getValue());
389 }
390 });
391
392 return ZippedFlowImpl.create(tuples);
393 }
394
395 /**
396 * Creates a lazy Flow that returns integers in the given range. The range starts
397 * with the lower value and counts by 1 up to the upper range (which is not part of
398 * the Flow). If lower equals upper, the Flow is empty. If upper is less than lower,
399 * the Flow counts down instead.
400 *
401 * @param lower
402 * start of range (inclusive)
403 * @param upper
404 * end of range (exclusive)
405 */
406 public static Flow<Integer> range(int lower, int upper)
407 {
408 if (lower == upper)
409 return F.emptyFlow();
410
411 if (lower < upper)
412 return lazy(new LazyRange(lower, upper, 1));
413
414 return lazy(new LazyRange(lower, upper, -1));
415 }
416
417 /**
418 * Creates a {@link Flow} from a {@linkplain LazyFunction lazy function}.
419 */
420 public static <T> Flow<T> lazy(LazyFunction<T> function)
421 {
422 assert function != null;
423
424 return new LazyFlow<T>(function);
425 }
426
427 private static <T> LazyFunction<T> toLazyFunction(final T currentValue, final Mapper<T, T> function)
428 {
429 return new LazyFunction<T>()
430 {
431 @Override
432 public LazyContinuation<T> next()
433 {
434 final T nextValue = function.map(currentValue);
435
436 return new LazyContinuation<T>(nextValue, toLazyFunction(nextValue, function));
437 }
438 };
439 }
440
441 /**
442 * Creates an infinite lazy flow from an initial value and a function to map from the current value to the
443 * next value.
444 *
445 * @param initial
446 * initial value in flow
447 * @param function
448 * maps from current value in flow to next value in flow
449 * @return lazy flow
450 */
451 public static <T> Flow<T> iterate(final T initial, final Mapper<T, T> function)
452 {
453 LazyFunction<T> head = new LazyFunction<T>()
454 {
455 @Override
456 public LazyContinuation<T> next()
457 {
458 return new LazyContinuation<T>(initial, toLazyFunction(initial, function));
459 }
460 };
461
462 return lazy(head);
463 }
464
465 /**
466 * Creates an <em>infinite</em> series of numbers.
467 *
468 * Attempting to get the {@linkplain Flow#count()} of the series will form an infinite loop.
469 */
470 public static Flow<Integer> series(int start, final int delta)
471 {
472 return iterate(start, new Mapper<Integer, Integer>()
473 {
474 @Override
475 public Integer map(Integer element)
476 {
477 return element + delta;
478 }
479 });
480 }
481
482 /**
483 * A Worker factory; the returnedWorker adds the values to a provided collection.
484 */
485 public static <T> Worker<T> addToCollection(final Collection<T> coll)
486 {
487 return new Worker<T>()
488 {
489 @Override
490 public void work(T value)
491 {
492 coll.add(value);
493 }
494 };
495 }
496
497 /**
498 * A Predicate factory for matching String elements with a given prefix.
499 *
500 * @since 5.3
501 */
502 public static Predicate<String> startsWith(String prefix)
503 {
504 return startsWith(prefix, false);
505 }
506
507 /**
508 * As {@link #startsWith(String)}, but ignores case.
509 *
510 * @since 5.3
511 */
512 public static Predicate<String> startsWithIgnoringCase(String prefix)
513 {
514 return startsWith(prefix, true);
515 }
516
517 /**
518 * @since 5.3
519 */
520 private static Predicate<String> startsWith(final String prefix, final boolean ignoreCase)
521 {
522 return new Predicate<String>()
523 {
524 @Override
525 public boolean accept(String element)
526 {
527 return element.regionMatches(ignoreCase, 0, prefix, 0, prefix.length());
528 }
529 };
530 }
531
532 /**
533 * A Predicate factory for matching String elements with a given suffix.
534 *
535 * @since 5.3
536 */
537 public static Predicate<String> endsWith(String suffix)
538 {
539 return endsWith(suffix, false);
540 }
541
542 /**
543 * As with {@link #endsWith(String)} but ignores case.
544 *
545 * @since 5.3
546 */
547 public static Predicate<String> endsWithIgnoringCase(String suffix)
548 {
549 return endsWith(suffix, true);
550 }
551
552 /**
553 * @since 5.3
554 */
555 private static Predicate<String> endsWith(final String suffix, final boolean ignoreCase)
556 {
557 return new Predicate<String>()
558 {
559 @Override
560 public boolean accept(String element)
561 {
562 return element
563 .regionMatches(ignoreCase, element.length() - suffix.length(), suffix, 0, suffix.length());
564 }
565 };
566 }
567
568 /**
569 * Creates a Comparator for the Tuples of a {@link ZippedFlow} that sorts the Tuple elements based on the first
570 * value in the Tuple.
571 *
572 * @since 5.3
573 */
574 public static <A extends Comparable<A>, B> Comparator<Tuple<A, B>> orderByFirst()
575 {
576 return new Comparator<Tuple<A, B>>()
577 {
578 @Override
579 public int compare(Tuple<A, B> o1, Tuple<A, B> o2)
580 {
581 return o1.first.compareTo(o2.first);
582 }
583 };
584 }
585
586 /**
587 * Creates a Comparator for the Tuples of a {@link ZippedFlow} that sorts the Tuple elements based on the first
588 * value in the Tuple.
589 *
590 * @since 5.3
591 */
592 public static <A, B extends Comparable<B>> Comparator<Tuple<A, B>> orderBySecond()
593 {
594 return new Comparator<Tuple<A, B>>()
595 {
596 @Override
597 public int compare(Tuple<A, B> o1, Tuple<A, B> o2)
598 {
599 return o1.second.compareTo(o2.second);
600 }
601 };
602 }
603
604 /**
605 * Inverts a predicate.
606 *
607 * @param delegate
608 * the predicate to invert
609 * @return a new predicate that is inverse to the existing predicate
610 * @since 5.3
611 */
612 public static <T> Predicate<T> not(final Predicate<? super T> delegate)
613 {
614 assert delegate != null;
615
616 return new Predicate<T>()
617 {
618 @Override
619 public boolean accept(T element)
620 {
621 return !delegate.accept(element);
622 }
623 };
624 }
625
626 /**
627 * Combines two mappers into a composite mapping from type A to type C via type B.
628 *
629 * @param abMapper
630 * maps from A to B
631 * @param bcMapper
632 * maps from B to C
633 * @return mapper from A to C
634 */
635 public static <A, B, C> Mapper<A, C> combine(final Mapper<A, B> abMapper, final Mapper<B, C> bcMapper)
636 {
637 assert abMapper != null;
638 assert bcMapper != null;
639
640 return new Mapper<A, C>()
641 {
642
643 @Override
644 public C map(A aElement)
645 {
646 B bElement = abMapper.map(aElement);
647
648 return bcMapper.map(bElement);
649 }
650
651 };
652 }
653
654 /**
655 * Combines any number of delegates as a logical and operation. Evaluation terminates
656 * with the first delegate predicate that returns false.
657 *
658 * @param delegates
659 * to evaluate
660 * @return combined delegate
661 * @since 5.3
662 */
663 public static <T> Predicate<T> and(final Predicate<? super T>... delegates)
664 {
665 return new Predicate<T>()
666 {
667 @Override
668 public boolean accept(T element)
669 {
670 for (Predicate<? super T> delegate : delegates)
671 {
672 if (!delegate.accept(element))
673 return false;
674 }
675
676 return true;
677 }
678 };
679 }
680
681 /**
682 * Combines any number of delegates as a logical or operation. Evaluation terminates
683 * with the first delegate predicate that returns true.
684 *
685 * @param delegates
686 * to evaluate
687 * @return combined delegate
688 * @since 5.3
689 */
690 public static <T> Predicate<T> or(final Predicate<? super T>... delegates)
691 {
692 return new Predicate<T>()
693 {
694 @Override
695 public boolean accept(T element)
696 {
697 for (Predicate<? super T> delegate : delegates)
698 {
699 if (delegate.accept(element))
700 return true;
701 }
702
703 return false;
704 }
705 };
706 }
707
708 /**
709 * Combines several compatible workers together into a composite.
710 *
711 * @since 5.3
712 */
713 public static <T> Worker<T> combine(final Worker<? super T>... delegates)
714 {
715 assert delegates.length > 0;
716
717 return new Worker<T>()
718 {
719 @Override
720 public void work(T value)
721 {
722 for (Worker<? super T> delegate : delegates)
723 {
724 delegate.work(value);
725 }
726 }
727 };
728 }
729 }